home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 076-100 / 091 / adlcomp / adlcomp.c next >
C/C++ Source or Header  |  1995-03-18  |  22KB  |  716 lines

  1.     /***************************************************************\
  2.     *                                *
  3.     *    adlcomp.c - ADL compiler.  See the ADL documentation    *
  4.     *    for information about ADL.                *
  5.     *        Copyright 1987 by Ross Cunniff            *
  6.     *                                *
  7.     \***************************************************************/
  8.  
  9. #include <stdio.h>
  10. #include <fcntl.h>
  11. #include <ctype.h>
  12.  
  13. #include "adltypes.h"
  14.  
  15. #if UNIX
  16. #  include <signal.h>
  17. #endif
  18.  
  19. #include "adlprog.h"
  20. #include "builtins.h"
  21. #include "adldef.h"
  22. #include "vstring.h"
  23. #include "virtmem.h"
  24. #include "adlcomp.h"
  25.  
  26. #define MAXDIR 4            /* Maximum number of -i dirs    */
  27.  
  28. #if UNIX
  29. char    *S_VAL = "adlsXXXXXX",        /* See below - patched        */
  30.     *CODE  = "adlcXXXXXX",        /* to use mktmp( 3 )        */
  31.     *tmpdir= "/tmp",        /* Default to /tmp        */
  32.     *PATH_SEPS = "/",        /* Set of path separators    */
  33.     *LAST_SEP = "/";        /* Final separator        */
  34. #endif
  35.  
  36. #if MSDOS
  37. char    *S_VAL = "adlsval.tmp",        /* Temporary string file    */
  38.     *CODE  = "adlcode.tmp",        /* Temporary code file        */
  39.     *tmpdir= "",            /* Default to current dir    */
  40.     *PATH_SEPS = ":/\\",        /* Set of path separators    */
  41.     *LAST_SEP = "\\";        /* Final separator        */
  42. #endif
  43.  
  44. #if AMIGA
  45. char
  46.     *S_VAL = "adlsval.tmp",        /* Ditto above            */
  47.     *CODE  = "adlcode.tmp",        /* Ditto            */
  48.     *tmpdir= "RAM:",        /* Default to RAM:        */
  49.     *PATH_SEPS = ":/",        /* Set of path separators    */
  50.     *LAST_SEP = "/";        /* Final separator        */
  51. #endif
  52.  
  53. char    tmp_s[ 256 ],            /* Combined path and base    */
  54.     tmp_c[ 256 ],            /*   of CODE and S_VAL        */
  55.     *outname = "adlcomp.out",    /* Default output file name    */
  56.     *dirnames[MAXDIR];        /* -i names            */
  57.  
  58. extern    char    *calloc();        /* Memory allocator        */
  59.  
  60. struct    pagetab    codetab;        /* Structure for virtual code    */
  61.  
  62. int16    NUM_VARS = 64,            /* Default # of ADL variables    */
  63.     NUM_ROUTS = 512,        /* Default # of ADL routines    */
  64.     NUM_OBJS = 256,            /* Default # of ADL objects    */
  65.     NUM_VERBS = 128,        /* Default # of ADL verbs    */
  66.     NUM_STR = 1024,            /* Default # of ADL strings    */
  67.     NUM_PREP = 8,            /* Default # of prep synonyms    */
  68.     NUM_VS = 8,            /* Default # of verb synonyms    */
  69.  
  70.     numprep,            /* Actual # of prep synonyms    */
  71.     header,                /* Produce a status line?    */
  72.     debugging,            /* Retain symbols?        */
  73.     filenum,            /* String index of file name    */
  74.     numdir;                /* Number of -i dirs specified    */
  75.  
  76. int    S_VAL_F,            /* String paging file        */
  77.     CODE_F;                /* Code paging file        */
  78.  
  79. #if MSDOS
  80. unsigned
  81.     _stack = 10000;            /* Large default stack size    */
  82. #endif
  83.  
  84.     /***************************************************************\
  85.     *                                *
  86.     *    main() - The main routine.  Opens files, initializes    *
  87.     *    structures, compiles the code, writes the result.    *
  88.     *    Pretty simple, no?                    *
  89.     *                                *
  90.     \***************************************************************/
  91.  
  92. main( argc, argv )
  93. int    argc;
  94. char    *argv[];
  95. {
  96.     getadlargs( argc, argv );        /* Get command line args    */
  97.     init();                /* Initialize structures    */
  98.  
  99.     /* Print the copyright message */
  100.     fputs( "ADL compiler - Version 3.2 - June 7, 1987\n", stderr );
  101.     fputs( "Copyright 1985, 1986, 1987 by Ross Cunniff\n", stderr );
  102.     fputs( "All rights reserved\n", stderr );
  103.     fflush( stderr );
  104.  
  105.     adlcomp();                /* Compile the source        */
  106.     strcpy( token, "EOF" );        /* Indicate we're at EOF    */
  107.     write_code();            /* Write the code file        */
  108.     wrapup();                /* Close files            */
  109.     exit( numerr );            /* Return the number of errors    */
  110. }
  111.  
  112.  
  113.     /***************************************************************\
  114.     *                                *
  115.     *    getadlargs( argc, argv ) - extract meaning from        *
  116.     *    the command line.  See the adlcomp man page for        *
  117.     *    more information.                    *
  118.     *                                *
  119.     \***************************************************************/
  120.  
  121. getadlargs( argc, argv )
  122. int    argc;
  123. char    *argv[];
  124. {
  125.     int    i;
  126.     char ch;
  127.     char *getnext();
  128.  
  129. #if MSDOS
  130.     argv[ 0 ] = "adlcomp";        /* MSDOS has no notion of argv[ 0 ] */
  131. #endif
  132.  
  133.     if( argc < 2 )
  134.     /* We must at least specify an input file */
  135.     print_usage( argv[ 0 ] );
  136.  
  137.     /* Check each argument */
  138.     for( i = 1; i < argc; i++ ) {
  139.     if( *argv[ i ] == '-' ) {
  140.         ch = *++argv[ i ];
  141.         if( isupper( ch ) )
  142.         ch = tolower( ch );
  143.         switch( ch ) {
  144.         case 'e' : maxerr    = atoi( getnext( argv, &i ) );    break;
  145.         case 'g' : NUM_VARS    = atoi( getnext( argv, &i ) );    break;
  146.         case 'm' : NUM_STR    = atoi( getnext( argv, &i ) );    break;
  147.         case 'n' : NUM_OBJS    = atoi( getnext( argv, &i ) );    break;
  148.         case 'p' : NUM_PREP    = atoi( getnext( argv, &i ) );    break;
  149.         case 'r' : NUM_ROUTS    = atoi( getnext( argv, &i ) );    break;
  150.         case 's' : NUM_VS    = atoi( getnext( argv, &i ) );    break;
  151.         case 'v' : NUM_VERBS    = atoi( getnext( argv, &i ) );    break;
  152.  
  153.         case 'i' : if( numdir >= MAXDIR )
  154.                    fatal( "Too many -i options\n" );
  155.                dirnames[ numdir++ ] = getnext( argv, &i );
  156.                break;
  157.         case 'o' : outname    =       getnext( argv, &i );    break;
  158.         case 't' : tmpdir    =    getnext( argv, &i );    break;
  159.  
  160.         case 'w' : wignore    = 1;                break;
  161.         case 'd' : debugging    = 1;                break;
  162.         case 'h' : header    = 1;                break;
  163.  
  164.         default  : print_usage( argv[ 0 ] );
  165.         }
  166.     }
  167.     else if( *inname )
  168.         print_usage( argv[ 0 ] );
  169.     else
  170.         strcpy( inname, argv[ i ] );
  171.     }
  172.     if( !*inname )
  173.     print_usage( argv[ 0 ] );
  174. }
  175.  
  176.  
  177.     /***************************************************************\
  178.     *                                *
  179.     *    print_usage( cname ) - print the USAGE error message    *
  180.     *                                *
  181.     \***************************************************************/
  182.  
  183. print_usage( cname )
  184. char
  185.     *cname;
  186. {
  187.     fprintf( stderr, "Usage: %s Infile (with any of the following)\n", cname );
  188.     fprintf( stderr, "    -o Outfile        File for output\n" );
  189.     fprintf( stderr, "    -i Dir            Directory for INCLUDEs\n" );
  190.     fprintf( stderr, "    -t Dir            Directory for temp files\n" );
  191.     fprintf( stderr, "    -d            Output debugging info\n" );
  192.     fprintf( stderr, "    -w            Suppress warnings\n" );
  193.     fprintf( stderr, "    -e N            Max # of errors\n" );
  194.     fprintf( stderr, "    -g N            Max # of globals\n" );
  195.     fprintf( stderr, "    -m N            Max # of strings\n" );
  196.     fprintf( stderr, "    -n N            Max # of objects\n" );
  197.     fprintf( stderr, "    -p N            Max # of prep phrases\n" );
  198.     fprintf( stderr, "    -r N            Max # of routines\n" );
  199.     fprintf( stderr, "    -s N            Max # of verb phrases\n" );
  200.     fprintf( stderr, "    -v N            Max # of verbs\n" );
  201.     exit( 1 );
  202. }
  203.  
  204.  
  205.     /***************************************************************\
  206.     *                                *
  207.     *    getnext( argv, indx ) - get the next string from    *
  208.     *    argv, whether it be the rest of the current arg        *
  209.     *    or the next arg.  This is to allow arguments like    *
  210.     *    "-ifoo" and "-i foo" to be equivalent.            *
  211.     *                                *
  212.     \***************************************************************/
  213.  
  214. char *
  215. getnext( argv, indx )
  216. char    *argv[];
  217. int    *indx;
  218. {
  219.     if( *++argv[ *indx ] )
  220.     return argv[ *indx ];
  221.     else
  222.     return argv[ ++*indx ];
  223. }
  224.  
  225.  
  226.     /***************************************************************\
  227.     *                                *
  228.     *    init() - initialize the structures and files.        *
  229.     *                                *
  230.     \***************************************************************/
  231.  
  232. init()
  233. {
  234.     /* Initialize the object sizes */
  235.     hdr.nounindex.objsize    = sizeof( int16 );
  236.     hdr.symindex.objsize    = sizeof( struct symbol );
  237.     hdr.verbindex.objsize    = sizeof( struct verbrec );
  238.     hdr.objindex.objsize    = sizeof( struct objrec );
  239.     hdr.prepindex.objsize    = sizeof( struct preprec );
  240.     hdr.vsindex.objsize        = sizeof( struct vp_syn );
  241.     hdr.routindex.objsize    = sizeof( address );
  242.     hdr.varindex.objsize    = sizeof( int16 );
  243.     hdr.codeindex.objsize    = 512;
  244.     hdr.strtabindex.objsize    = sizeof( int32 );
  245.     hdr.strindex.objsize    = 512;
  246.   
  247.     /* Allocate space for the arrays */
  248.     varspace    = (int16 *)           calloc(hdr.varindex.objsize, NUM_VARS);
  249.     routspace    = (address *)           calloc(hdr.routindex.objsize,NUM_ROUTS);
  250.     verbspace    = (struct verbrec *)   calloc(hdr.verbindex.objsize,NUM_VERBS);
  251.     nounspace    = (int16 *)           calloc(hdr.nounindex.objsize,NUM_OBJS);
  252.     objspace    = (struct objrec *)    calloc(hdr.objindex.objsize, NUM_OBJS);
  253.     prepspace    = (struct preprec *)   calloc(hdr.prepindex.objsize,NUM_PREP);
  254.     verbsyn    = (struct vp_syn *)    calloc(hdr.vsindex.objsize,  NUM_VS);
  255.     str_tab    = (int32 *)           calloc(hdr.strtabindex.objsize,NUM_STR);
  256.  
  257.     /* Check the memory allocation */
  258.     if(        (varspace    == (int16 *)        0)        ||
  259.         (routspace    == (address *)        0)        ||
  260.         (verbspace    == (struct verbrec *)    0)        ||
  261.         (objspace    == (struct objrec *)    0)        ||
  262.         (nounspace    == (int16 *)        0)        ||
  263.         (prepspace    == (struct preprec *)    0)        ||
  264.         (verbsyn    == (struct vp_syn *)    0)        ||
  265.         (str_tab    == (int32 *)        0)        )
  266.     fatal( "Out of memory.\n" );
  267.  
  268.     /* Make the temporary names */
  269.     mkpath( tmp_s, tmpdir, S_VAL );
  270.     mkpath( tmp_c, tmpdir, CODE );
  271.  
  272.     /* Initialize the virtual code & string routines */
  273. #if UNIX
  274.     mktemp( tmp_s );
  275.     mktemp( tmp_c );
  276. #endif
  277.     S_VAL_F = open( tmp_s, WB );
  278.     CODE_F = open( tmp_c, WB );
  279.     if( (S_VAL_F < 0) || (CODE_F < 0) )
  280.     fatal( "Unable to open temporary files.\n" );
  281.  
  282.     vsinit( S_VAL_F, 0L, 0,(char *)NULL,(char *)NULL,(int16 *)NULL, str_tab );
  283.     vm_init( CODE_F, 0L, &codetab, 1 );
  284.  
  285.     /* Set up some initial values */
  286.     NUMOBJ = 2;                /* .ALL and STRING */
  287.     NUMNOUN = 1;            /* Skip the null noun */
  288.     NUMVERB = 2;            /* TELLER and NOVERB */
  289.     NUMROUT = 4;            /* NULL, DWIMD, DWIMI, and START */
  290.     numprep = 1;            /* Skip the null preposition */
  291.     objspace[ _ALL ].cont = _STRING;
  292.  
  293.     /* Set up the input file */
  294.     if( open_input( inname ) == 0 ) {
  295.     fprintf( stderr, "Error opening input file %s\n", inname );
  296.     exit( -1 );
  297.     }
  298.     filenum = newstr( inname );
  299.  
  300.     /* Initialize the dictionary */
  301.     init_predefs();
  302. }
  303.  
  304.  
  305.     /***************************************************************\
  306.     *                                *
  307.     *    breaker() - handle a signal                *
  308.     *                                *
  309.     \***************************************************************/
  310.  
  311. breaker()
  312. {
  313.     printf( "***BREAK***\n" );
  314.     close( S_VAL_F );    close( CODE_F );
  315.     unlink( tmp_s );    unlink( tmp_c );
  316.     exit( -1 );
  317. }
  318.  
  319.  
  320.     /***************************************************************\
  321.     *                                *
  322.     *    adlcomp() - the heart of the compiler.  Reads tokens    *
  323.     *    from the current input file, processing them until    *
  324.     *    EOF or until the maximum number of errors has been    *
  325.     *    exceeded.  Parsing is done with recursive descent.    *
  326.     *                                *
  327.     \***************************************************************/
  328.  
  329. adlcomp()
  330. {
  331.     printf( "Reading from file %s\n", inname );
  332.     fflush( stdout );
  333.     while( 1 ) {
  334.     lexer();            /* Read a token            */
  335.     if( t_type == EOF ) {
  336.         printf( "Done reading file %s\n", inname );
  337.         fflush( stdout );
  338.         return;
  339.     }
  340.  
  341.     if( (t_type >= MIN_D) && (t_type <= MAX_D) )
  342.         /* This is one of PREP, ADJEC, etc.  Handle them generically */
  343.         getlist( t_type );
  344.     else {
  345.         /* We need to special case the declaration. */
  346.         switch( t_type ) {
  347.         case VAR_D    : getvars();        break;
  348.         case NOUN_D    : getnouns();        break;
  349.         case UNDECLARED    : getassign( 1 );    break;
  350.         case INCLUDE    : getfile();        break;
  351.         case MESSAGE    : printmsg();        break;
  352.         case VERB    : getverb();        break;
  353.         case ADJEC    :
  354.         case NOUN    :
  355.         case NOUN_SYN    : nounassign( 1, 0 );    break;
  356.         case '('    : globassign();        break;
  357.         case ROUTINE    : routassign();        break;
  358.         case PREP    : prepassign();        break;
  359.         default        : error( ILLEGAL_SYMBOL );
  360.                   eatuntil( ';' );
  361.         }    /* switch */
  362.     }    /* else */
  363.     }        /* while */
  364. }        /* adlcomp */
  365.  
  366.  
  367.     /***************************************************************\
  368.     *                                *
  369.     *    printmsg() - executes the MESSAGE directive, and    *
  370.     *    prints a message on the user's terminal.        *
  371.     *                                *
  372.     \***************************************************************/
  373.  
  374. printmsg()
  375. {
  376.     lexer();                /* Get a token.            */
  377.     if( t_type != STRING )
  378.     _ERR_FIX( "Illegal compile time message.\n", ';' );
  379.     fputs( token + 1, stderr );        /* Print the token.        */
  380.     fflush( stderr );
  381.     lexer();
  382.     if( t_type != ';' )            /* Expect a following semicolon    */
  383.     _ERR_FIX( SEMI_EXPECTED, ';' );
  384. }
  385.  
  386.  
  387.     /***************************************************************\
  388.     *                                *
  389.     *    getfile() - handle the INCLUDE directive, reading    *
  390.     *    from the appropriate file.                *
  391.     *                                *
  392.     \***************************************************************/
  393.  
  394. getfile()
  395. {
  396.     char *fsave;
  397.     char msg[ 80 ], nsave[ 512 ], t_in[ 512 ], *sprintf();
  398.     int16 lsave, numsave, i, found;
  399.  
  400.     lexer();                /* Get a token.            */
  401.     if( t_type != STRING )
  402.     _ERR_FIX( "File name expected for INCLUDE.\n", ';' );
  403.     save_input( &fsave );        /* Save the current input file    */
  404.     strcpy( nsave, inname );        /* Save the current input name    */
  405.     lsave = numline;            /* Save the current line number    */
  406.     numsave = filenum;            /* Save the current file number    */
  407.     strcpy( inname, virtstr( t_val ) );    /* Get the rep. of the new name    */
  408.     filenum = t_val;            /* Get the new file number    */
  409.     numline = 1;            /* Set the new line number    */
  410.  
  411.     /* Try to find the file in the current directory. */
  412.     found = 0;
  413.     if( open_input( inname ) == 0 ) {
  414.     /* Couldn't find it.  Try to find it in the -i directories */
  415.     for( i = 0; i < numdir; i++ ) {
  416.         mkpath( t_in, dirnames[ i ], inname );
  417.         if( open_input( t_in ) != 0 ) {
  418.         found = 1;
  419.         break;
  420.         }
  421.     }
  422.     if( !found ) {
  423.         sprintf( msg, "Error opening file \"%s\".\n", inname );
  424.         fatal( msg );
  425.     }
  426.     strcpy( inname, t_in );
  427.     }
  428.     adlcomp();            /* Recursively compile the new file.    */
  429.     close_input();        /* Close the file            */
  430.     restore_input( fsave );    /* Restore the old input file        */
  431.     numline = lsave;        /* Restore the old line number        */
  432.     strcpy( inname, nsave );    /* Restore the old file name        */
  433.     filenum = numsave;        /* Restore the old file number        */
  434.     lexer();            /* Get a token.                */
  435.     if( t_type != ';' )        /* Expect a ';' after the INCLUDE    */
  436.     _ERR_FIX( SEMI_EXPECTED, ';' );
  437. }
  438.  
  439.  
  440. mkpath( s, dir, base )
  441. char
  442.     *s,
  443.     *dir,
  444.     *base;
  445. {
  446.     int
  447.     len,
  448.     sep_found;
  449.     char
  450.     *check;
  451.  
  452.     /* Copy the directory name into the string */
  453.     strcpy( s, dir );
  454.     len = strlen( s ) - 1;
  455.  
  456.     /* Check to see if the name has a path separator at the end */
  457.     check = PATH_SEPS;
  458.     sep_found = 0;
  459.     while( *check ) {
  460.     if( s[ len ] == *check ) {
  461.         sep_found = 1;
  462.         break;
  463.     }
  464.     check++;
  465.     }
  466.     if( !sep_found )
  467.     /* Add the separator */
  468.     strcat( s, LAST_SEP );
  469.  
  470.     /* Concatenate the base name onto the string */
  471.     strcat( s, base );
  472. }
  473.  
  474.  
  475.     /***************************************************************\
  476.     *                                *
  477.     *    check_predefs() - check to see whether DWIMI, DWIMD,    *
  478.     *    START, STRING, and TELLER have been defined.  Also,    *
  479.     *    check the current number of various things against    *
  480.     *    their maximum.                        *
  481.     *                                *
  482.     \***************************************************************/
  483.  
  484. check_predefs()
  485. {
  486.     if( !routspace[ _START ] )
  487.     error( "START undefined.\n" );
  488.     if( !routspace[ _DWIMI ] )
  489.     warning( "DWIMI undefined.\n" );
  490.     if( !routspace[ _DWIMD ] )
  491.     warning( "DWIMD undefined.\n" );
  492.     if( !objspace[ _STRING ].props[ _ACTION - 17 ] )
  493.     warning( "STRING undefined.\n" );
  494.     if( !(verbspace[ _TELLER ].preact||verbspace[ _TELLER ].postact) )
  495.     warning( "TELLER undefined.\n" );
  496.     if( !(verbspace[ _NOVERB ].preact||verbspace[ _NOVERB ].postact) )
  497.     warning( "NOVERB undefined.\n" );
  498.     checkmax( NUMVAR, NUM_VARS, "VARs" );
  499.     checkmax( NUMROUT, NUM_ROUTS, "routines" );
  500.     checkmax( NUMOBJ, NUM_OBJS, "objects" );
  501.     checkmax( NUMVERB, NUM_VERBS, "verbs" );
  502.     checkmax( NUMSTR, NUM_STR, "strings" );
  503.     checkmax( NUMPP, NUM_PREP, "prep synonyms" );
  504.     checkmax( NUMVS, NUM_VS, "[verb prep] synonyms" );
  505. }
  506.  
  507.     /***************************************************************\
  508.     *                                *
  509.     *    checkmax( n, max_n, name ) - checks n against max_n,    *
  510.     *    and prints an appropriate message if n > max_n.        *
  511.     *                                *
  512.     \***************************************************************/
  513.  
  514. checkmax( n, max_n, name )
  515. int
  516.     n, max_n;
  517. char
  518.     *name;
  519. {
  520.     printf( "%d out of %d %s used\n", n, max_n, name );
  521.     fflush( stdout );
  522.     if( n > max_n )
  523.     error( "Number of %s is greater than %d!\n", name );
  524. }
  525.  
  526.  
  527.     /***************************************************************\
  528.     *                                *
  529.     *    write_code() - write out the ADL executable.        *
  530.     *                                *
  531.     \***************************************************************/
  532.  
  533. write_code()
  534. {
  535.     int outf;        /* The actual file being written        */
  536.     int32 temp;        /* Temporary area for long int calculations    */
  537.     int cmask;        /* Value of the umask call            */
  538.     int32 time();    /* Current time stamp.                */
  539.  
  540.     /* Flush out all dirty pages to disk. */
  541.     vsflush();
  542.     vm_flush( &codetab );
  543.  
  544.     /* Tie up a few loose ends */
  545.     hdr.strtabindex.numobjs = numstr();
  546.     temp = currcode();
  547.     hdr.codeindex.numobjs = (temp / 512L) + 1;
  548.     temp = numchar();
  549.     hdr.strindex.numobjs = (temp / 512L) + 1;
  550.  
  551.     /* Make sure all is OK */
  552.     check_predefs();
  553.  
  554.     /* Don't write any code if errors were encountered. */
  555.     if( numerr )
  556.     return;
  557.  
  558.     /* Set up the file pointers */
  559.     hdr.symindex.ptr    = sizeof( struct header );
  560.     count_symtab( debugging );
  561.     hdr.verbindex.ptr    = hdr.symindex.ptr    +
  562.                    hdr.symindex.objsize    * NUMSYM;
  563.     hdr.objindex.ptr    = hdr.verbindex.ptr   +
  564.                 hdr.verbindex.objsize   * NUMVERB;
  565.     hdr.nounindex.ptr    = hdr.objindex.ptr +
  566.                 hdr.objindex.objsize    * NUMOBJ;
  567.     hdr.varindex.ptr    = hdr.nounindex.ptr   +
  568.                 hdr.nounindex.objsize    * NUMNOUN;
  569.     hdr.prepindex.ptr    = hdr.varindex.ptr    +
  570.                 hdr.varindex.objsize    * NUMVAR;
  571.     hdr.vsindex.ptr    = hdr.prepindex.ptr   +
  572.                 hdr.prepindex.objsize    * NUMPP;
  573.     hdr.routindex.ptr    = hdr.vsindex.ptr   +
  574.                 hdr.vsindex.objsize    * NUMVS;
  575.     hdr.codeindex.ptr    = hdr.routindex.ptr   +
  576.                 hdr.routindex.objsize   * NUMROUT;
  577.     hdr.strtabindex.ptr    = hdr.codeindex.ptr   +
  578.                 hdr.codeindex.numobjs   * 512;
  579.     hdr.strindex.ptr    = hdr.strtabindex.ptr +
  580.                 hdr.strtabindex.objsize * NUMSTR;
  581.   
  582.     /* Set the timestamp and the magic number */
  583.     hdr.adlid = time( 0 );
  584.     hdr.magic = M_ADL;
  585.     sprintf( hdr.adlname, "#! %s%s%s\n", ADL_NAME,
  586.            (header?" -h":"\0"),
  587.            (debugging?" -d":"\0") );
  588.  
  589.     /* Write the file */
  590.     if( (outf = open( outname, WB )) < 0 )
  591.     fatal( "Error writing to output file.\n" );
  592.     adlstats();
  593.     lseek( outf, 0L, 0 );
  594.     write( outf, &hdr, sizeof( struct header ) );
  595.     write_symtab( outf, debugging );
  596.     writebuf( outf, verbspace,    &hdr.verbindex );
  597.     writebuf( outf, objspace,    &hdr.objindex );
  598.     writebuf( outf, nounspace,    &hdr.nounindex );
  599.     writebuf( outf, varspace,    &hdr.varindex );
  600.     writebuf( outf, prepspace,    &hdr.prepindex );
  601.     writebuf( outf, verbsyn,    &hdr.vsindex );
  602.     writebuf( outf, routspace,    &hdr.routindex );
  603.     writestuff( CODE_F, outf,    &hdr.codeindex );
  604.     writebuf( outf, str_tab, &hdr.strtabindex );
  605.     writestuff( S_VAL_F, outf,    &hdr.strindex );
  606.  
  607.     /* Close the file */
  608.     close( outf );
  609.  
  610. #if UNIX
  611.     /* Make it executable */
  612.     cmask = umask( 0 );
  613.     (void)umask( cmask );
  614.     chmod( outname, (0777 & (~cmask)) );
  615. #endif
  616. }
  617.  
  618.  
  619.     /***************************************************************\
  620.     *                                *
  621.     *    adlstats() - print some statistics about the        *
  622.     *    compilation                        *
  623.     *                                *
  624.     \***************************************************************/
  625.  
  626. adlstats()
  627. {
  628.     int i;
  629.     printf( "adlcomp %s -o %s ", inname, outname );
  630.     printf( "-g %d -r %d ", NUMVAR+1, NUMROUT+1 );
  631.     printf( "-v %d -n %d -m %d ", NUMVERB+1, NUMOBJ+1, NUMSTR+1 );
  632.     printf( "-p %d -s %d%s%s", NUMPP, NUMVS,
  633.         (wignore?" -w":""),(debugging?" -d":"") );
  634.  
  635.     for( i = 0; i < numdir; i++ )
  636.     printf( " -i %s", dirnames[ i ] );
  637.     printf( "\nWriting %ld bytes\n",
  638.         hdr.strindex.ptr + 512*hdr.strindex.numobjs );
  639.     fflush( stdout );
  640. }
  641.  
  642.  
  643.     /***************************************************************\
  644.     *                                *
  645.     *    writebuf( f, b, d ) - write the buffer b to the file    *
  646.     *    f, given the information in the header structure d.    *
  647.     *                                *
  648.     \***************************************************************/
  649.  
  650. /*VARARGS 1*/
  651. writebuf( f, b, d )
  652. int    f;
  653. char    *b;
  654. struct    adldir    *d;
  655. {
  656.     lseek( f, 0L, 2 );                /* Seek to EOF        */
  657.     write( f, b, d->numobjs * d->objsize );    /* Write the data    */
  658. }
  659.  
  660.  
  661.     /***************************************************************\
  662.     *                                *
  663.     *    writestuff( ifile, ofile, dir ) - Copy data from    *
  664.     *    ifile to ofile, according to the information in dir.    *
  665.     *                                *
  666.     \***************************************************************/
  667.  
  668. writestuff( ifile, ofile, dir )
  669. int    ifile, ofile;
  670. struct    adldir    *dir;
  671. {
  672.     int32 t, i, n, r;
  673.     char buf[ 512 ];
  674.  
  675.     t = dir->numobjs * dir->objsize;
  676.     n = t / 512;            /* Write in 512 byte chunks    */
  677.     r = t % 512;            /* Number of remaining bytes    */
  678.     for( i = 0; i < n; i++ ) {
  679.     lseek( ifile, (long)(i*512), 0 );
  680.     read( ifile, buf, 512 );
  681.     lseek( ofile, 0L, 2 );        /* Seek to EOF             */
  682.     write( ofile, buf, 512 );
  683.     }
  684.     if( r ) {
  685.     /* Write the remaining bytes */
  686.     lseek( ifile, (long)(n*512), 0 );
  687.     read( ifile, buf, 512 );
  688.     lseek( ofile, 0L, 2 );        /* Seek to EOF            */
  689.     write( ofile, buf, 512 );
  690.     }
  691.     close( ifile );            /* Close the input file.    */
  692. }
  693.  
  694.  
  695.     /***************************************************************\
  696.     *                                *
  697.     *    wrapup() - clean up our mess and go home.        *
  698.     *                                *
  699.     \***************************************************************/
  700.  
  701. wrapup()
  702. {
  703.     char *ep, *wp;
  704.  
  705.     /* Remove the temporary files. */
  706.     unlink( tmp_s ); unlink( tmp_c );
  707.  
  708.     /* Print how many errors and warnings we've encountered. */
  709.     ep = ( (numerr == 1) ? "" : "s" );
  710.     wp = ( (numwarn == 1) ? "" : "s" );
  711.     printf( "adlcomp complete. %d error%s, %d warning%s.\n", numerr, ep,
  712.         numwarn, wp );
  713. }
  714.  
  715. /*** EOF adlcomp.c ***/
  716.